{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 数据处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 安装类库\n",
    "# !mkdir /home/aistudio/external-libraries\n",
    "# !pip install imgaug -t /home/aistudio/external-libraries\n",
    "import sys\n",
    "sys.path.append('/home/aistudio/external-libraries')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "image shape: (32, 32, 3)\n",
      "label value: cattle\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import paddle\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "import imgaug as ia\n",
    "import imgaug.augmenters as iaa\n",
    "\n",
    "# 读取数据\n",
    "reader = paddle.batch(\n",
    "    paddle.dataset.cifar.train100(),\n",
    "    batch_size=8) # 数据集读取器\n",
    "data = next(reader()) # 读取数据\n",
    "index = 0 # 批次索引\n",
    "\n",
    "# 读取图像\n",
    "image = np.array([x[0] for x in data]).astype(np.float32) # 读取图像数据，数据类型为float32\n",
    "image = image * 255 # 从[0,1]转换到[0,255]\n",
    "image = image[index].reshape((3, 32, 32)).transpose((1, 2, 0)).astype(np.uint8) # 数据格式从CHW转换为HWC，数据类型转换为uint8\n",
    "print('image shape:', image.shape)\n",
    "\n",
    "# 图像增强\n",
    "# sometimes = lambda aug: iaa.Sometimes(0.5, aug) # 随机进行图像增强\n",
    "# seq = iaa.Sequential([\n",
    "#     sometimes(iaa.CropAndPad(px=(-4, 4))),      # 随机裁剪填充像素\n",
    "#     iaa.Fliplr(0.5)])                           # 随机进行水平翻转\n",
    "# image = seq(image=image)\n",
    "\n",
    "# 读取标签\n",
    "label = np.array([x[1] for x in data]).astype(np.int64) # 读取标签数据，数据类型为int64\n",
    "vlist = ['beaver', 'dolphin', 'otter', 'seal', 'whale',\n",
    "         'aquarium fish', 'flatfish', 'ray', 'shark', 'trout',\n",
    "         'orchids', 'poppies', 'roses', 'sunflowers', 'tulips',\n",
    "         'bottles', 'bowls', 'cans', 'cups', 'plates',\n",
    "         'apples', 'mushrooms', 'oranges', 'pears', 'sweet peppers',\n",
    "         'clock', 'keyboard', 'lamp', 'telephone', 'television',\n",
    "         'bed', 'chair', 'couch', 'table', 'wardrobe',\n",
    "         'bee', 'beetle', 'butterfly', 'caterpillar', 'cockroach',\n",
    "         'bear', 'leopard', 'lion', 'tiger', 'wolf',\n",
    "         'bridge', 'castle', 'house', 'road', 'skyscraper',\n",
    "         'cloud', 'forest', 'mountain', 'plain', 'sea',\n",
    "         'camel', 'cattle', 'chimpanzee', 'elephant', 'kangaroo',\n",
    "         'fox', 'porcupine', 'possum', 'raccoon', 'skunk',\n",
    "         'crab', 'lobster', 'snail', 'spider', 'worm',\n",
    "         'baby', 'boy', 'girl', 'man', 'woman',\n",
    "         'crocodile', 'dinosaur', 'lizard', 'snake', 'turtle',\n",
    "         'hamster', 'mouse', 'rabbit', 'shrew', 'squirrel',\n",
    "         'maple', 'oak', 'palm', 'pine', 'willow',\n",
    "         'bicycle', 'bus', 'motorcycle', 'pickup truck', 'train',\n",
    "         'lawn-mower', 'rocket', 'streetcar', 'tank', 'tractor'] # 标签名称列表\n",
    "vlist.sort() # 字母上升排序\n",
    "print('label value:', vlist[label[index]])\n",
    "\n",
    "# 显示图像\n",
    "image = Image.fromarray(image)   # 转换图像格式\n",
    "image.save('./work/out/img.png') # 保存读取图像\n",
    "plt.figure(figsize=(3, 3))       # 设置显示大小\n",
    "plt.imshow(image)                # 设置显示图像\n",
    "plt.show()                       # 显示图像文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_data: image shape (128, 3, 32, 32), label shape:(128, 1)\n",
      "valid_data: image shape (128, 3, 32, 32), label shape:(128, 1)\n"
     ]
    }
   ],
   "source": [
    "import paddle\n",
    "import numpy as np\n",
    "import imgaug as ia\n",
    "import imgaug.augmenters as iaa\n",
    "\n",
    "# 训练数据增强\n",
    "def train_augment(images):\n",
    "    # 转换格式\n",
    "    images = images * 255 # 从[0,1]转换到[0,255]\n",
    "    images = images.transpose((0, 2, 3, 1)).astype(np.uint8) # 数据格式从BCHW转换为BHWC，数据类型转换为uint8\n",
    "    \n",
    "    # 增强图像\n",
    "    sometimes = lambda aug: iaa.Sometimes(0.5, aug) # 随机进行图像增强\n",
    "    seq = iaa.Sequential([\n",
    "        sometimes(iaa.CropAndPad(px=(-4, 4))),      # 随机裁剪填充像素\n",
    "        iaa.Fliplr(0.5)])                           # 随机进行水平翻转\n",
    "    images = seq(images=images)\n",
    "    \n",
    "    # 减去均值\n",
    "    mean = np.array([0.4914, 0.4822, 0.4465]).reshape((1, 1, 1, -1)) # cifar数据集通道平均值\n",
    "    stdv = np.array([0.2471, 0.2435, 0.2616]).reshape((1, 1, 1, -1)) # cifar数据集通道标准差\n",
    "    \n",
    "    images = (images/255.0 - mean) / stdv # 对图像进行归一化\n",
    "    images = images.transpose((0, 3, 1, 2)).astype(np.float32) # 数据格式从BHWC转换为BCHW，数据类型转换为float32\n",
    "    \n",
    "    return images\n",
    "\n",
    "# 验证数据增强\n",
    "def valid_augment(images):\n",
    "    # 转换格式\n",
    "    images = images * 255 # 从[0,1]转换到[0,255]\n",
    "    images = images.transpose((0, 2, 3, 1)).astype(np.uint8) # 数据格式从BCHW转换为BHWC，数据类型转换为uint8\n",
    "    \n",
    "    # 减去均值\n",
    "    mean = np.array([0.4914, 0.4822, 0.4465]).reshape((1, 1, 1, -1)) # cifar数据集通道平均值\n",
    "    stdv = np.array([0.2471, 0.2435, 0.2616]).reshape((1, 1, 1, -1)) # cifar数据集通道标准差\n",
    "    \n",
    "    images = (images/255.0 - mean) / stdv # 对图像进行归一化\n",
    "    images = images.transpose((0, 3, 1, 2)).astype(np.float32) # 数据格式从BHWC转换为BCHW，数据类型转换为float32\n",
    "    \n",
    "    return images\n",
    "\n",
    "# 读取训练数据\n",
    "train_reader = paddle.batch(\n",
    "    paddle.reader.shuffle(paddle.dataset.cifar.train100(), buf_size=50000),\n",
    "    batch_size=128) # 构造数据读取器\n",
    "train_data = next(train_reader()) # 读取训练数据\n",
    "\n",
    "train_image = np.array([x[0] for x in train_data]).reshape((-1, 3, 32, 32)).astype(np.float32) # 读取训练图像\n",
    "train_image = train_augment(train_image)                                                       # 训练图像增强\n",
    "train_label = np.array([x[1] for x in train_data]).reshape((-1, 1)).astype(np.int64)           # 读取训练标签\n",
    "print('train_data: image shape {}, label shape:{}'.format(train_image.shape, train_label.shape))\n",
    "\n",
    "# 读取验证数据\n",
    "valid_reader = paddle.batch(\n",
    "    paddle.dataset.cifar.test100(),\n",
    "    batch_size=128) # 构造数据读取器\n",
    "valid_data = next(valid_reader()) # 读取验证数据\n",
    "\n",
    "valid_image = np.array([x[0] for x in valid_data]).reshape((-1, 3, 32, 32)).astype(np.float32) # 读取验证图像\n",
    "valid_image = valid_augment(valid_image)                                                       # 验证图像增强\n",
    "valid_label = np.array([x[1] for x in valid_data]).reshape((-1, 1)).astype(np.int64)           # 读取验证标签\n",
    "print('valid_data: image shape {}, label shape:{}'.format(valid_image.shape, valid_label.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 模型设计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import paddle.fluid as fluid\n",
    "from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear, BatchNorm\n",
    "import math\n",
    "\n",
    "# 模组结构：输入维度，输出维度，滑动步长，基础长度, 队列长度\n",
    "group_arch = [(3, 256, 1, 2, 1), (256, 256, 2, 2, 1), (256, 256, 2, 2, 1)]\n",
    "group_dim  = 256 # 模组输出维度\n",
    "class_dim  = 100 # 类别数量维度\n",
    "\n",
    "# 卷积单元\n",
    "class ConvUnit(fluid.dygraph.Layer):\n",
    "    def __init__(self, in_dim, out_dim, filter_size=3, stride=1, act=None):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化卷积单元，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "            in_dim      - 输入维度\n",
    "            out_dim     - 输出维度\n",
    "            filter_size - 卷积大小\n",
    "            stride      - 滑动步长\n",
    "            act         - 激活函数\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(ConvUnit, self).__init__()\n",
    "        \n",
    "        # 添加卷积\n",
    "        self.conv = Conv2D(\n",
    "            num_channels=in_dim,\n",
    "            num_filters=out_dim,\n",
    "            filter_size=filter_size,\n",
    "            stride=stride,\n",
    "            padding=(filter_size-1)//2,                       # 输出特征图大小不变\n",
    "            param_attr=fluid.initializer.MSRA(uniform=False), # 使用MARA 初始权重\n",
    "            bias_attr=False,                                  # 卷积输出没有偏置项\n",
    "            act=None)\n",
    "        \n",
    "        # 添加正则\n",
    "        self.norm = BatchNorm(\n",
    "            num_channels=out_dim,\n",
    "            param_attr=fluid.initializer.Constant(1.0), # 使用常量初始化权重\n",
    "            bias_attr=fluid.initializer.Constant(0.0),  # 使用常量初始化偏置\n",
    "            act=act)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征进行卷积和正则\n",
    "        输入:\n",
    "            x - 输入特征\n",
    "        输出:\n",
    "            x - 输出特征\n",
    "        \"\"\"\n",
    "        # 进行卷积\n",
    "        x = self.conv(x)\n",
    "        \n",
    "        # 进行正则\n",
    "        x = self.norm(x)\n",
    "        \n",
    "        return x\n",
    "\n",
    "# 投影单元\n",
    "class ProjUnit(fluid.dygraph.Layer):\n",
    "    def __init__(self, in_dim, out_dim, filter_size=1, stride=1, act=None):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化投影单元，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "            in_dim      - 输入维度\n",
    "            out_dim     - 输出维度\n",
    "            filter_size - 卷积大小\n",
    "            stride      - 滑动步长\n",
    "            act         - 激活函数\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(ProjUnit, self).__init__()\n",
    "        \n",
    "        # 添加池化\n",
    "        self.pool = Pool2D(\n",
    "            pool_size=filter_size,\n",
    "            pool_stride=stride,\n",
    "            pool_padding=0,\n",
    "            pool_type='avg')\n",
    "        \n",
    "        # 添加卷积\n",
    "        self.conv = Conv2D(\n",
    "            num_channels=in_dim,\n",
    "            num_filters=out_dim,\n",
    "            filter_size=1,\n",
    "            stride=1,\n",
    "            padding=0,\n",
    "            param_attr=fluid.initializer.MSRA(uniform=False), # 使用MARA 初始权重\n",
    "            bias_attr=False,                                  # 卷积输出没有偏置项\n",
    "            act=None)\n",
    "        \n",
    "        # 添加正则\n",
    "        self.norm = BatchNorm(\n",
    "            num_channels=out_dim,\n",
    "            param_attr=fluid.initializer.Constant(1.0), # 使用常量初始化权重\n",
    "            bias_attr=fluid.initializer.Constant(0.0),  # 使用常量初始化偏置\n",
    "            act=act)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征进行池化卷积和正则\n",
    "        输入:\n",
    "            x - 输入特征\n",
    "        输出:\n",
    "            x - 输出特征\n",
    "        \"\"\"\n",
    "        # 进行池化\n",
    "        x = self.pool(x)\n",
    "        \n",
    "        # 进行卷积\n",
    "        x = self.conv(x)\n",
    "        \n",
    "        # 进行正则\n",
    "        x = self.norm(x)\n",
    "        \n",
    "        return x\n",
    "\n",
    "# 队列结构\n",
    "class SSRQueue(fluid.dygraph.Layer):\n",
    "    def __init__(self, in_dim, out_dim, stride=1, queues=2, act=None):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化队列结构，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "            in_dim  - 输入维度\n",
    "            out_dim - 输出维度\n",
    "            stride  - 滑动步长，1保持不变，2下采样\n",
    "            queues  - 队列长度，分割尺度为2^(n-1)\n",
    "            act     - 激活函数\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(SSRQueue, self).__init__()\n",
    "        \n",
    "        # 添加队列变量\n",
    "        self.queues = queues # 队列长度\n",
    "        self.split_list = [] # 分割列表\n",
    "        \n",
    "        # 添加队列列表\n",
    "        self.queue_list = [] # 队列列表\n",
    "        for i in range(queues):\n",
    "            # 添加队列项目\n",
    "            queue_item = self.add_sublayer( # 构造队列项目\n",
    "                'queue_' + str(i),\n",
    "                ConvUnit(\n",
    "                    in_dim=(in_dim if i==0 else out_dim), # 每组队列项目除第一个外，in_dim=out_dim\n",
    "                    out_dim=out_dim,\n",
    "                    filter_size=3,\n",
    "                    stride=(stride if i==0 else 1), # 每组队列项目除第一块外，stride=1\n",
    "                    act=act))\n",
    "            self.queue_list.append(queue_item) # 添加队列项目\n",
    "            \n",
    "            # 计算输出维度\n",
    "            if i < (queues-1): # 如果不是最后一项\n",
    "                out_dim = out_dim//2 # 输出维度减半\n",
    "                self.split_list.append(out_dim) # 添加分割列表\n",
    "            \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征图像提取特征\n",
    "        输入:\n",
    "            x - 输入特征\n",
    "        输出:\n",
    "            x - 输出特征\n",
    "        \"\"\"\n",
    "        # 提取特征\n",
    "        x_list = [] # 队列输出列表\n",
    "        for i, queue_item in enumerate(self.queue_list):\n",
    "            if i < (self.queues-1): # 如果不是最后一项\n",
    "                x = queue_item(x) # 提取队列特征\n",
    "                x_item, x = fluid.layers.split(input=x, num_or_sections=[-1, self.split_list[i]], dim=1)\n",
    "                x_list.append(x_item) # 添加输出列表\n",
    "            else: # 否则不对特征分割\n",
    "                x = queue_item(x) # 提取队列特征\n",
    "                x_list.append(x) # 添加输出列表\n",
    "        \n",
    "        # 联结特征\n",
    "        x = fluid.layers.concat(input=x_list, axis=1) # 队列输出列表按通道维进行特征联结\n",
    "        \n",
    "        return x\n",
    "    \n",
    "# 基础结构\n",
    "class SSRBasic(fluid.dygraph.Layer):\n",
    "    def __init__(self, in_dim, out_dim, stride=1, queues=1, is_pass=True):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化基础结构，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "            in_dim  - 输入维度\n",
    "            out_dim - 输出维度\n",
    "            stride  - 滑动步长\n",
    "            queues  - 队列长度\n",
    "            is_pass - 是否直连\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(SSRBasic, self).__init__()\n",
    "        \n",
    "        # 是否直连标识\n",
    "        self.is_pass = is_pass\n",
    "        \n",
    "        # 添加投影路径\n",
    "        self.proj = ProjUnit(in_dim=in_dim, out_dim=out_dim, filter_size=stride, stride=stride, act=None)\n",
    "        \n",
    "        # 添加卷积路径\n",
    "        if queues==1:\n",
    "            self.conv = ConvUnit(in_dim=in_dim, out_dim=out_dim, filter_size=3, stride=stride, act='relu')\n",
    "        else:\n",
    "            self.conv = SSRQueue(in_dim=in_dim, out_dim=out_dim, stride=stride, queues=queues, act='relu')\n",
    "        \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征图像提取特征\n",
    "        输入:\n",
    "            x - 输入特征\n",
    "        输出:\n",
    "            x - 输出特征\n",
    "            y - 输出特征\n",
    "        \"\"\"\n",
    "        # 直连路径\n",
    "        if self.is_pass: # 是否直连\n",
    "            x_pass = x\n",
    "        else:            # 否则投影\n",
    "            x_pass = self.proj(x)\n",
    "        \n",
    "        # 卷积路径\n",
    "        x_conv = self.conv(x)\n",
    "        \n",
    "        # 输出特征\n",
    "        x = fluid.layers.elementwise_add(x=x_pass, y=x_conv, act=None) # 直连路径与卷积路径进行特征相加\n",
    "        y = x\n",
    "        \n",
    "        return x, y\n",
    "    \n",
    "# 模块结构\n",
    "class SSRBlock(fluid.dygraph.Layer):\n",
    "    def __init__(self, in_dim, out_dim, stride=1, basics=1, queues=1):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化模块结构，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "            in_dim  - 输入维度\n",
    "            out_dim - 输出维度\n",
    "            stride  - 滑动步长\n",
    "            basics  - 基础长度\n",
    "            queues  - 队列长度\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(SSRBlock, self).__init__()\n",
    "        \n",
    "        # 添加模块列表\n",
    "        self.block_list = [] # 模块列表\n",
    "        for i in range(basics):\n",
    "            block_item = self.add_sublayer( # 构造模块项目\n",
    "                'block_' + str(i),\n",
    "                SSRBasic(\n",
    "                    in_dim=(in_dim if i==0 else out_dim), # 每组模块项目除第一块外，输入维度=输出维度\n",
    "                    out_dim=out_dim,\n",
    "                    stride=(stride if i==0 else 1), # 每组模块项目除第一块外，stride=1\n",
    "                    queues=queues,\n",
    "                    is_pass=(False if i==0 else True))) # 每组模块项目除第一块外，is_pass=True\n",
    "            self.block_list.append(block_item) # 添加模块项目\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征图像提取特征\n",
    "        输入:\n",
    "            x      - 输入特征\n",
    "        输出:\n",
    "            x      - 输出特征\n",
    "            y_list - 输出特征列表\n",
    "        \"\"\"\n",
    "        y_list = [] # 模块输出列表\n",
    "        for block_item in self.block_list:\n",
    "            x, y_item = block_item(x) # 提取模块特征\n",
    "            y_list.append(y_item) # 添加输出列表\n",
    "            \n",
    "        return x, y_list\n",
    "\n",
    "# 模组结构\n",
    "class SSRGroup(fluid.dygraph.Layer):\n",
    "    def __init__(self):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化模组结构，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(SSRGroup, self).__init__()\n",
    "        \n",
    "        # 添加模组列表\n",
    "        self.group_list = [] # 模组列表\n",
    "        for i, block_arch in enumerate(group_arch):\n",
    "            group_item = self.add_sublayer( # 构造模组项目\n",
    "                'group_' + str(i),\n",
    "                SSRBlock(\n",
    "                    in_dim=block_arch[0],\n",
    "                    out_dim=block_arch[1],\n",
    "                    stride=block_arch[2],\n",
    "                    basics=block_arch[3],\n",
    "                    queues=block_arch[4]))\n",
    "            self.group_list.append(group_item) # 添加模组项目\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入的特征图像提取特征\n",
    "        输入:\n",
    "            x      - 输入特征\n",
    "        输出:\n",
    "            x      - 输出特征\n",
    "            y_list - 输出特征列表\n",
    "        \"\"\"\n",
    "        y_list = [] # 模组输出列表\n",
    "        for group_item in self.group_list:\n",
    "            x, y_item = group_item(x) # 提取模组特征\n",
    "            y_list.append(y_item) # 添加输出列表\n",
    "            \n",
    "        return x, y_list\n",
    "        \n",
    "# 分割网络\n",
    "class SSRNet(fluid.dygraph.Layer):\n",
    "    def __init__(self):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            初始化分割网络，H/W=(H/W+2*P-F)/S+1\n",
    "        输入:\n",
    "        输出:\n",
    "        \"\"\"\n",
    "        super(SSRNet, self).__init__()\n",
    "        \n",
    "        # 添加模组结构\n",
    "        self.backbone = SSRGroup() # 输出：N*C*H*W\n",
    "        \n",
    "        # 添加全连接层\n",
    "        self.pool = Pool2D(global_pooling=True, pool_type='avg') # 输出：N*C*1*1\n",
    "        \n",
    "        stdv = 1.0/(math.sqrt(group_dim)*1.0)                    # 设置均匀分布权重方差\n",
    "        self.fc = Linear(                                        # 输出：=N*10\n",
    "            input_dim=group_dim,\n",
    "            output_dim=class_dim,\n",
    "            param_attr=fluid.initializer.Uniform(-stdv, stdv),   # 使用均匀分布初始权重\n",
    "            bias_attr=fluid.initializer.Constant(0.0),           # 使用常量数值初始偏置\n",
    "            act='softmax')\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        功能:\n",
    "            对输入图像进行分类\n",
    "        输入:\n",
    "            x - 输入图像\n",
    "        输出:\n",
    "            x - 预测结果\n",
    "        \"\"\"\n",
    "        # 提取特征\n",
    "        x, y_list = self.backbone(x)\n",
    "        \n",
    "        # 进行预测\n",
    "        x = self.pool(x)\n",
    "        x = fluid.layers.reshape(x, [x.shape[0], -1])\n",
    "        x = self.fc(x)\n",
    "        \n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tatol param: 3322468\n",
      "infer shape: [1, 100]\n"
     ]
    }
   ],
   "source": [
    "import paddle.fluid as fluid\n",
    "from paddle.fluid.dygraph.base import to_variable\n",
    "import numpy as np\n",
    "\n",
    "with fluid.dygraph.guard():\n",
    "    # 输入数据\n",
    "    x = np.random.randn(1, 3, 32, 32).astype(np.float32)\n",
    "    x = to_variable(x)\n",
    "    \n",
    "    # 进行预测\n",
    "    backbone = SSRNet() # 设置网络\n",
    "    \n",
    "    infer = backbone(x) # 进行预测\n",
    "    \n",
    "    # 显示结果\n",
    "    parameters = 0\n",
    "    for p in backbone.parameters():\n",
    "        parameters += np.prod(p.shape) # 统计参数\n",
    "    \n",
    "    print('tatol param:', parameters)\n",
    "    print('infer shape:', infer.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "complete - train time: 9751s, best epoch: 184, best loss: 1.265366, best accuracy: 69.31%\r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import paddle\n",
    "import paddle.fluid as fluid\n",
    "from paddle.utils.plot import Ploter\n",
    "import numpy as np\n",
    "import time\n",
    "import math\n",
    "import os\n",
    "\n",
    "epoch_num = 300   # 训练周期，取值一般为[1,300]\n",
    "train_batch = 128 # 训练批次，取值一般为[1,256]\n",
    "valid_batch = 128 # 验证批次，取值一般为[1,256]\n",
    "displays = 100    # 显示迭代\n",
    "\n",
    "start_lr = 0.00001                         # 开始学习率，取值一般为[1e-8,5e-1]\n",
    "based_lr = 0.1                             # 基础学习率，取值一般为[1e-8,5e-1]\n",
    "epoch_iters = math.ceil(50000/train_batch) # 每轮迭代数\n",
    "warmup_iter = 10 * epoch_iters             # 预热迭代数，取值一般为[1,10]\n",
    "\n",
    "momentum = 0.9     # 优化器动量\n",
    "l2_decay = 0.00005 # 正则化系数，取值一般为[1e-5,5e-4]\n",
    "epsilon = 0.05     # 标签平滑率，取值一般为[1e-2,1e-1]\n",
    "\n",
    "checkpoint = False                   # 断点标识\n",
    "model_path = './work/out/ssrnet'     # 模型路径\n",
    "result_txt = './work/out/result.txt' # 结果文件\n",
    "class_num  = 100                     # 类别数量\n",
    "\n",
    "with fluid.dygraph.guard():\n",
    "    # 准备数据\n",
    "    train_reader = paddle.batch(\n",
    "        reader=paddle.reader.shuffle(reader=paddle.dataset.cifar.train100(), buf_size=50000),\n",
    "        batch_size=train_batch)\n",
    "    \n",
    "    valid_reader = paddle.batch(\n",
    "        reader=paddle.dataset.cifar.test100(),\n",
    "        batch_size=valid_batch)\n",
    "    \n",
    "    # 声明模型\n",
    "    model = SSRNet()\n",
    "    \n",
    "    # 优化算法\n",
    "    consine_lr = fluid.layers.cosine_decay(based_lr, epoch_iters, epoch_num) # 余弦衰减策略\n",
    "    decayed_lr = fluid.layers.linear_lr_warmup(consine_lr, warmup_iter, start_lr, based_lr) # 线性预热策略\n",
    "    \n",
    "    optimizer = fluid.optimizer.Momentum(\n",
    "        learning_rate=decayed_lr,                           # 衰减学习策略\n",
    "        momentum=momentum,                                  # 优化动量系数\n",
    "        regularization=fluid.regularizer.L2Decay(l2_decay), # 正则衰减系数\n",
    "        parameter_list=model.parameters())\n",
    "    \n",
    "    # 加载断点\n",
    "    if checkpoint: # 是否加载断点文件\n",
    "        model_dict, optimizer_dict = fluid.load_dygraph(model_path) # 加载断点参数\n",
    "        model.set_dict(model_dict)                                  # 设置权重参数\n",
    "        optimizer.set_dict(optimizer_dict)                          # 设置优化参数\n",
    "    else:          # 否则删除结果文件\n",
    "        if os.path.exists(result_txt): # 如果存在结果文件\n",
    "            os.remove(result_txt)      # 那么删除结果文件\n",
    "    \n",
    "    # 初始训练\n",
    "    avg_train_loss = 0 # 平均训练损失\n",
    "    avg_valid_loss = 0 # 平均验证损失\n",
    "    avg_valid_accu = 0 # 平均验证精度\n",
    "    \n",
    "    iterator = 1                                # 迭代次数\n",
    "    train_prompt = \"Train loss\"                 # 训练标签\n",
    "    valid_prompt = \"Valid loss\"                 # 验证标签\n",
    "    ploter = Ploter(train_prompt, valid_prompt) # 训练图像\n",
    "    \n",
    "    best_epoch = 0           # 最好周期\n",
    "    best_accu = 0            # 最好精度\n",
    "    best_loss = 100.0        # 最好损失\n",
    "    train_time = time.time() # 训练时间\n",
    "    \n",
    "    # 开始训练\n",
    "    for epoch_id in range(epoch_num):\n",
    "        # 训练模型\n",
    "        model.train() # 设置训练\n",
    "        for batch_id, train_data in enumerate(train_reader()):\n",
    "            # 读取数据\n",
    "            image_data = np.array([x[0] for x in train_data]).reshape((-1, 3, 32, 32)).astype(np.float32) # 读取图像数据\n",
    "            image_data = train_augment(image_data)                                                        # 使用数据增强\n",
    "            image = fluid.dygraph.to_variable(image_data)                                                 # 转换数据类型\n",
    "\n",
    "            label_data = np.array([x[1] for x in train_data]).astype(np.int64)                        # 读取标签数据\n",
    "            label = fluid.dygraph.to_variable(label_data)                                             # 转换数据类型\n",
    "            label = fluid.layers.label_smooth(label=fluid.one_hot(label, class_num), epsilon=epsilon) # 使用标签平滑\n",
    "            label.stop_gradient = True                                                                # 停止梯度传播\n",
    "\n",
    "            # 前向传播\n",
    "            infer = model(image)\n",
    "            \n",
    "            # 计算损失\n",
    "            loss = fluid.layers.cross_entropy(infer, label, soft_label=True)\n",
    "            train_loss = fluid.layers.mean(loss)\n",
    "            \n",
    "            # 反向传播\n",
    "            train_loss.backward()\n",
    "            optimizer.minimize(train_loss)\n",
    "            model.clear_gradients()\n",
    "            \n",
    "            # 显示结果\n",
    "            if iterator % displays == 0:\n",
    "                # 显示图像\n",
    "                avg_train_loss = train_loss.numpy()[0]                # 设置训练损失\n",
    "                ploter.append(train_prompt, iterator, avg_train_loss) # 添加训练图像\n",
    "                ploter.plot()                                         # 显示训练图像\n",
    "                \n",
    "                # 打印结果\n",
    "                print(\"iteration: {:6d}, epoch: {:3d}, train loss: {:.6f}, valid loss: {:.6f}, valid accuracy: {:.2%}\".format(\n",
    "                    iterator, epoch_id+1, avg_train_loss, avg_valid_loss, avg_valid_accu))\n",
    "                \n",
    "                # 写入文件\n",
    "                with open(result_txt, 'a') as file:\n",
    "                    file.write(\"iteration: {:6d}, epoch: {:3d}, train loss: {:.6f}, valid loss: {:.6f}, valid accuracy: {:.2%}\\n\".format(\n",
    "                        iterator, epoch_id+1, avg_train_loss, avg_valid_loss, avg_valid_accu))\n",
    "            \n",
    "            # 增加迭代\n",
    "            iterator += 1\n",
    "            \n",
    "        # 验证模型\n",
    "        valid_loss_list = [] # 验证损失列表\n",
    "        valid_accu_list = [] # 验证精度列表\n",
    "        \n",
    "        model.eval()   # 设置验证\n",
    "        for batch_id, valid_data in enumerate(valid_reader()):\n",
    "            # 读取数据\n",
    "            image_data = np.array([x[0] for x in valid_data]).reshape((-1, 3, 32, 32)).astype(np.float32) # 读取图像数据\n",
    "            image_data = valid_augment(image_data)                                                        # 使用图像增强\n",
    "            image = fluid.dygraph.to_variable(image_data)                                                 # 转换数据类型\n",
    "            \n",
    "            label_data = np.array([x[1] for x in valid_data]).reshape((-1, 1)).astype(np.int64) # 读取标签数据\n",
    "            label = fluid.dygraph.to_variable(label_data)                                       # 转换数据类型\n",
    "            label.stop_gradient = True                                                          # 停止梯度传播\n",
    "            \n",
    "            # 前向传播\n",
    "            infer = model(image)\n",
    "            \n",
    "            # 计算精度\n",
    "            valid_accu = fluid.layers.accuracy(infer,label)\n",
    "            \n",
    "            valid_accu_list.append(valid_accu.numpy())\n",
    "            \n",
    "            # 计算损失\n",
    "            loss = fluid.layers.cross_entropy(infer, label)\n",
    "            valid_loss = fluid.layers.mean(loss)\n",
    "            \n",
    "            valid_loss_list.append(valid_loss.numpy())\n",
    "        \n",
    "        # 设置结果\n",
    "        avg_valid_accu = np.mean(valid_accu_list)             # 设置验证精度\n",
    "        \n",
    "        avg_valid_loss = np.mean(valid_loss_list)             # 设置验证损失\n",
    "        ploter.append(valid_prompt, iterator, avg_valid_loss) # 添加训练图像\n",
    "        \n",
    "        # 保存模型\n",
    "        fluid.save_dygraph(model.state_dict(), model_path)     # 保存权重参数\n",
    "        fluid.save_dygraph(optimizer.state_dict(), model_path) # 保存优化参数\n",
    "        \n",
    "        if avg_valid_loss < best_loss:\n",
    "            fluid.save_dygraph(model.state_dict(), model_path + '-best') # 保存权重\n",
    "            \n",
    "            best_epoch = epoch_id + 1                                    # 更新迭代\n",
    "            best_accu = avg_valid_accu                                   # 更新精度\n",
    "            best_loss = avg_valid_loss                                   # 更新损失\n",
    "    \n",
    "    # 显示结果\n",
    "    train_time = time.time() - train_time # 设置训练时间\n",
    "    print('complete - train time: {:.0f}s, best epoch: {:3d}, best loss: {:.6f}, best accuracy: {:.2%}'.format(\n",
    "        train_time, best_epoch, best_loss, best_accu))\n",
    "    \n",
    "    # 写入文件\n",
    "    with open(result_txt, 'a') as file:\n",
    "        file.write('complete - train time: {:.0f}s, best epoch: {:3d}, best loss: {:.6f}, best accuracy: {:.2%}\\n'.format(\n",
    "            train_time, best_epoch, best_loss, best_accu))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 模型预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "infer time: 0.004457s, infer value: cattle\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import paddle.fluid as fluid\n",
    "from PIL import Image\n",
    "import numpy as np\n",
    "import time\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "image_path = './work/out/img.png' # 图片路径\n",
    "model_path = './work/out/ssrnet-best' # 模型路径\n",
    "\n",
    "# 加载图像\n",
    "def load_image(image_path):\n",
    "    \"\"\"\n",
    "    功能:\n",
    "        读取图像并转换到输入格式\n",
    "    输入:\n",
    "        image_path - 输入图像路径\n",
    "    输出:\n",
    "        image - 输出图像\n",
    "    \"\"\"\n",
    "    # 读取图像\n",
    "    image = Image.open(image_path) # 打开图像文件\n",
    "    \n",
    "    # 转换格式\n",
    "    image = image.resize((32, 32), Image.ANTIALIAS) # 调整图像大小\n",
    "    image = np.array(image, dtype=np.float32) # 转换数据格式，数据类型转换为float32\n",
    "\n",
    "    # 减去均值\n",
    "    mean = np.array([0.4914, 0.4822, 0.4465]).reshape((1, 1, -1)) # cifar数据集通道平均值\n",
    "    stdv = np.array([0.2471, 0.2435, 0.2616]).reshape((1, 1, -1)) # cifar数据集通道标准差\n",
    "    \n",
    "    image = (image/255.0 - mean) / stdv # 对图像进行归一化\n",
    "    image = image.transpose((2, 0, 1)).astype(np.float32) # 数据格式从HWC转换为CHW，数据类型转换为float32\n",
    "    \n",
    "    # 增加维度\n",
    "    image = np.expand_dims(image, axis=0) # 增加数据维度\n",
    "    \n",
    "    return image\n",
    "\n",
    "# 预测图像\n",
    "with fluid.dygraph.guard():\n",
    "    # 读取图像\n",
    "    image = load_image(image_path)\n",
    "    image = fluid.dygraph.to_variable(image)\n",
    "    \n",
    "    # 加载模型\n",
    "    model = SSRNet()                               # 加载模型\n",
    "    model_dict, _ = fluid.load_dygraph(model_path) # 加载权重\n",
    "    model.set_dict(model_dict)                     # 设置权重\n",
    "    model.eval()                                   # 设置验证\n",
    "    \n",
    "    # 前向传播\n",
    "    infer_time = time.time()              # 推断开始时间\n",
    "    infer = model(image)\n",
    "    infer_time = time.time() - infer_time # 推断结束时间\n",
    "    \n",
    "    # 显示结果\n",
    "    vlist = ['beaver', 'dolphin', 'otter', 'seal', 'whale',\n",
    "             'aquarium fish', 'flatfish', 'ray', 'shark', 'trout',\n",
    "             'orchids', 'poppies', 'roses', 'sunflowers', 'tulips',\n",
    "             'bottles', 'bowls', 'cans', 'cups', 'plates',\n",
    "             'apples', 'mushrooms', 'oranges', 'pears', 'sweet peppers',\n",
    "             'clock', 'keyboard', 'lamp', 'telephone', 'television',\n",
    "             'bed', 'chair', 'couch', 'table', 'wardrobe',\n",
    "             'bee', 'beetle', 'butterfly', 'caterpillar', 'cockroach',\n",
    "             'bear', 'leopard', 'lion', 'tiger', 'wolf',\n",
    "             'bridge', 'castle', 'house', 'road', 'skyscraper',\n",
    "             'cloud', 'forest', 'mountain', 'plain', 'sea',\n",
    "             'camel', 'cattle', 'chimpanzee', 'elephant', 'kangaroo',\n",
    "             'fox', 'porcupine', 'possum', 'raccoon', 'skunk',\n",
    "             'crab', 'lobster', 'snail', 'spider', 'worm',\n",
    "             'baby', 'boy', 'girl', 'man', 'woman',\n",
    "             'crocodile', 'dinosaur', 'lizard', 'snake', 'turtle',\n",
    "             'hamster', 'mouse', 'rabbit', 'shrew', 'squirrel',\n",
    "             'maple', 'oak', 'palm', 'pine', 'willow',\n",
    "             'bicycle', 'bus', 'motorcycle', 'pickup truck', 'train',\n",
    "             'lawn-mower', 'rocket', 'streetcar', 'tank', 'tractor'] # 标签名称列表\n",
    "    vlist.sort() # 字母上升排序\n",
    "    print('infer time: {:f}s, infer value: {}'.format(infer_time, vlist[np.argmax(infer.numpy())]) )\n",
    "    \n",
    "    image = Image.open(image_path) # 打开图像文件\n",
    "    plt.figure(figsize=(3, 3))     # 设置显示大小\n",
    "    plt.imshow(image)              # 设置显示图像\n",
    "    plt.show()                     # 显示图像文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "PaddlePaddle 1.8.4 (Python 3.5)",
   "language": "python",
   "name": "py35-paddle1.2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
